//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Windows;
using OpenLS.Core;
using OpenLS.Core.Notification;
using OpenLS.Core.Serialization;
using OpenLS.Drawing;

namespace OpenLS.Chart
{
    public abstract class Axis : ViewModelBase,  IOfficeXmlSerializable,  IShape
    {
        private AxisPosition _axisPosition;
        private Crosses? _crosses = Chart.Crosses.AutoZero;
        private bool? _delete;
        private ChartLines _majorGridlines = new ChartLines();
        private TickMark _majorTickMark;
        private ChartLines _minorGridLines;

        private TickMark _minorTickMark;
        private NumericFormat _numericFormat;
        private Scaling _scaling;
        private ShapeProperties _shapeProperties;
        private TextBody _textBody;
        private TickLabelPosition _tickLabelPosition = TickLabelPosition.NextTo;
        private Title _title;

        protected Axis()
        {
            Id = (uint) Math.Abs(Guid.NewGuid().GetHashCode());
            Scaling = new Scaling();
        }

        public ChartLines MajorGridLines
        {
            get { return _majorGridlines; }
            set
            {
                _majorGridlines = value;
                notifyPropertyChanged("MajorGridLines");
            }
        }

        public ChartLines MinorGridLines
        {
            get { return _minorGridLines; }
            set
            {
                _minorGridLines = value;
                notifyPropertyChanged("MinorGridLines");
            }
        }


        public Axis CrossAxis { get; set; }

        public Crosses? Crosses
        {
            get { return _crosses; }
            set
            {
                _crosses = value;
                notifyPropertyChanged("Crosses");
            }
        }

        public double? CrossesAt { get; set; }

        public ExtensionElement Extension { get; set; }

        public TextBody TextProperties
        {
            get { return _textBody; }
            set
            {
                _textBody = value;
                notifyPropertyChanged("TextProperties");
            }
        }

        public Style Style
        {
            get
            {
                if (TextProperties == null)
                    return null;
                if (TextProperties.Paragraphs.Count == 0)
                    return null;
                TextParagraphProperties tpr = TextProperties.Paragraphs[0].TextParagraphProperties;
                if (tpr == null)
                    return null;
                return tpr.DpfRPr.Style;
            }
        }

        internal uint Id { get; set; }

        public Scaling Scaling
        {
            get { return _scaling; }
            set
            {
                _scaling = value;
                notifyPropertyChanged("Scaling");
                notifyPropertyChanged("Minimum");
                notifyPropertyChanged("Maximum");
                notifyPropertyChanged("Orientation");
            }
        }

        public AxisOrientation Orientation
        {
            get
            {
                if (_scaling != null)
                    return _scaling.Orientation;
                return AxisOrientation.MinimumToMaximum;
            }
            set
            {
                if (_scaling == null)
                    _scaling = new Scaling();
                _scaling.Orientation = value;
                notifyPropertyChanged("Orientation");
            }
        }

        public double? Maximum
        {
            get
            {
                if (_scaling == null)
                    return null;
                return _scaling.Maximum;
            }
            set
            {
                if (_scaling == null)
                    Scaling = new Scaling();
                Scaling.Maximum = value;
            }
        }

        public double? Minimum
        {
            get
            {
                if (_scaling == null)
                    return null;
                return _scaling.Minimum;
            }
            set
            {
                if (_scaling == null)
                    Scaling = new Scaling();
                Scaling.Minimum = value;
            }
        }

        public bool? Delete
        {
            get { return _delete; }
            set
            {
                _delete = value;
                notifyPropertyChanged("Delete");
                notifyPropertyChanged("IsVisible");
            }
        }

        public bool IsVisible
        {
            get
            {
                if (_delete == null)
                    return true;
                return !_delete.Value;
            }
        }

        public AxisPosition Position
        {
            get { return _axisPosition; }
            set
            {
                _axisPosition = value;
                notifyPropertyChanged("Position");
            }
        }

        public TickLabelPosition TickLabelPosition
        {
            get { return _tickLabelPosition; }
            set
            {
                _tickLabelPosition = value;
                notifyPropertyChanged("TickLabelPosition");
            }
        }

        public Title Title
        {
            get { return _title; }
            set
            {
                _title = value;
                notifyPropertyChanged("Title");
            }
        }

        public TickMark MajorTickMark
        {
            get { return _majorTickMark; }
            set
            {
                _majorTickMark = value;
                notifyPropertyChanged("MajorTickMark");
            }
        }

        public TickMark MinorTickMark
        {
            get { return _minorTickMark; }
            set
            {
                _minorTickMark = value;
                notifyPropertyChanged("MinorTickMark");
            }
        }

        public NumericFormat NumericFormat
        {
            get { return _numericFormat; }
            set
            {
                _numericFormat = value;
                notifyPropertyChanged("NumericFormat");
                notifyPropertyChanged("Format");
            }
        }

        public Format Format
        {
            get
            {
                if (_numericFormat == null)
                    return null;
                return _numericFormat.Format;
            }
        }

        #region INotifyPropertyChanged Members

        #endregion

        #region IOfficeXmlSerializable Members

        void IOfficeXmlSerializable.ReadXml(ReadContext context)
        {
            ReadXmlCore(context);
        }

        void IOfficeXmlSerializable.WriteXml(WriteContext context)
        {
            WriteXmlCore(context);
        }

        #endregion

        #region IShape Members

        public ShapeProperties ShapeProperties
        {
            get { return _shapeProperties; }
            set
            {
                _shapeProperties = value;
                notifyPropertyChanged("ShapeProperties");
            }
        }

        #endregion

        internal abstract void ReadXmlCore(ReadContext context);

        internal void ReadXmlBase(ReadContext context)
        {
            Id = context.ReadElementUIntegerAttribute("axId", "val");
            Scaling = context.ReadElement<Scaling>();
            bool found = true;
            while (found)
            {
                switch (context.ReaderLocalName)
                {
                    case "delete":
                        Delete = context.ReadOptionalElementBooleanAttribute("delete"); //\\default
                        break;
                    case "axPos":
                        Position = context.ReadElementEnumAttribute<AxisPosition>("axPos", "val");
                        break;
                    case "majorGridlines":
                        MajorGridLines = context.ReadOptionalElementAs<ChartLines>("majorGridlines");
                        break;
                    case "minorGridlines":
                        MinorGridLines = context.ReadOptionalElementAs<ChartLines>("minorGridlines");
                        break;
                    case "title":
                        Title = context.ReadOptionalElement<Title>("title");
                        break;
                    case "numFmt":
                        NumericFormat = context.ReadOptionalElement<NumericFormat>("numFmt");
                        break;
                    case "majorTickMark":
                        MajorTickMark =
                            context.ReadOptionalElementEnumAttribute("majorTickMark", "val", TickMark.None,
                                                                     TickMark.Cross); //\\ sure?
                        break;
                    case "minorTickMark":
                        MinorTickMark =
                            context.ReadOptionalElementEnumAttribute("minorTickMark", "val", TickMark.None,
                                                                     TickMark.Cross); //\\ sure?
                        break;
                    case "tickLblPos":
                        TickLabelPosition =
                            context.ReadOptionalElementEnumAttribute("tickLblPos", "val", TickLabelPosition.NextTo,
                                                                     TickLabelPosition.NextTo);
                        break;
                    case "spPr":
                        ShapeProperties = context.ReadOptionalElement<ShapeProperties>("spPr");
                        break;
                    case "txPr":
                        TextProperties = context.ReadOptionalElementAs<TextBody>("txPr");
                        break;
                    default:
                        found = false;
                        break;
                }
            }
            AxisResolver resolver = ReadContextData.GetAxisResolver(context);
            resolver.AddAction(context.ReadElementUIntegerAttribute("crossAx"), delegate(Axis a) { CrossAxis = a; });
            if (context.ReaderLocalName == "crosses")
            {
                _crosses = context.ReadElementEnumAttribute<Crosses>("crosses", "val");
            }
            else if (context.ReaderLocalName == "crossesAt")
            {
                _crosses = null;
                CrossesAt = context.ReadElementDoubleAttribute("crossesAt", "val");
            }
        }

        internal void WriteXmlBase(WriteContext context)
        {
            context.WriteElementUIntegerAttribute("axId", "val", Id);
            context.WriteOptionalElement(Scaling);
            if (Delete != null)
                context.WriteOptionalElementBooleanAttribute("delete", Delete.Value); //\\default
            context.WriteElementEnumAttribute("axPos", "val", Position);
            context.WriteOptionalElementAs(MajorGridLines, "majorGridlines");
            context.WriteOptionalElementAs(MinorGridLines, "minorGridlines");
            context.WriteOptionalElement(Title);
            context.WriteOptionalElement(NumericFormat);
            context.WriteOptionalElementEnumAttribute("majorTickMark", "val", MajorTickMark, TickMark.None,
                                                      TickMark.Cross);
            context.WriteOptionalElementEnumAttribute("minorTickMark", "val", MinorTickMark, TickMark.None,
                                                      TickMark.Cross);
            context.WriteOptionalElementEnumAttribute("tickLblPos", "val", TickLabelPosition,
                                                      TickLabelPosition.NextTo, TickLabelPosition.NextTo);
            context.WriteOptionalElement(ShapeProperties);
            context.WriteOptionalElementAs(TextProperties, "txPr");
            if (CrossAxis != null) //\\ check
                context.WriteElementUIntegerAttribute("crossAx", "val", CrossAxis.Id);
            if (Crosses != null)
            {
                context.WriteElementEnumAttribute("crosses", Crosses.Value);
            }
            else
                context.WriteElementDoubleAttribute("crossesAt", "val", CrossesAt.Value);
        }

        internal abstract void WriteXmlCore(WriteContext context);

    }
}